package com.mzj.saas.commons.util;

import java.nio.ByteBuffer;

public class BitUtils
{
	private static final int[] MASKS = new int[]{ 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01 } ;
	
	public static final byte[] readBytes( ByteBuffer buf, int offset, int fromBit, int numOfBits )
	{
		//read general byte binary bits use left align mode
		int fromByte = fromBit/8 ;
		int toBit = fromBit+numOfBits-1 ;//include toBit
		int toByte = toBit/8 ;
		int leftAlignOffset = fromBit%8 ;
		int rightMoveOffset = 8-leftAlignOffset ;
		int numOfBytes = (numOfBits+7)/8 ;
		int lastByteIdx = numOfBytes-1 ;

		buf.position( offset+fromByte ) ;
		
		byte[] arr = new byte[numOfBytes] ;
		
		if( leftAlignOffset == 0 )
		{
			buf.get( arr, 0, numOfBytes ) ;// already left align
			arr[lastByteIdx] = (byte)( (arr[lastByteIdx]&0xff) >>> (7-toBit%8) ) ;
		}
		else
		{
			int numOfReadBytes = toByte-fromByte+1 ;
			int idx = 0 ;
			
			int val = buf.get()&MASKS[leftAlignOffset] ;
			
			for( int i=1; i<numOfReadBytes; i++ )
			{
				val <<= 8 ;
				val |= (buf.get()&0xff) ;
				arr[idx++] = (byte)((val>>>rightMoveOffset)&0xff) ;
			}

			if( idx < numOfBytes )
			{
				arr[idx] = (byte)(val&MASKS[leftAlignOffset]) ;
				arr[lastByteIdx] = (byte)( (arr[lastByteIdx]&0xff) >>> (7-toBit%8) ) ;
			}
		}

		return arr ;
	}

	public static final long readLong( ByteBuffer buf, int offset, int fromBit, int numOfBits )
	{
		//use right align mode to read number binary bits
		int fromByte = fromBit/8 ;
		int toBit = fromBit+numOfBits-1 ;//include toBit
		int toByte = toBit/8 ;
		int numOfReadBytes = toByte-fromByte+1 ;
		int leftAlignOffset = fromBit%8 ;

		buf.position( offset+fromByte ) ;

		long val = buf.get()&MASKS[leftAlignOffset] ;
		
		for( int i=1; i<numOfReadBytes; i++ )
		{
			val <<= 8 ;
			val |= (buf.get()&0xff) ;
		}
		
		val >>>= (7-toBit%8) ;
		
		return val ;
	}

	public static final byte readByte( ByteBuffer buf, int offset, int fromBit, int numOfBits )
	{
		long val = readLong( buf, offset, fromBit, numOfBits ) ;
		return (byte)val ;
	}
	
	public static final short readShort( ByteBuffer buf, int offset, int fromBit, int numOfBits )
	{
		long val = readLong( buf, offset, fromBit, numOfBits ) ;
		return (short)val ;
	}
	
	public static final int readUShort( ByteBuffer buf, int offset, int fromBit, int numOfBits )
	{
		long val = readLong( buf, offset, fromBit, numOfBits ) ;
		return (int)val ;
	}
	
	public static final int readInt( ByteBuffer buf, int offset, int fromBit, int numOfBits )
	{
		long val = readLong( buf, offset, fromBit, numOfBits ) ;
		return (int)val ;
	}
	
	public static final long readUInt( ByteBuffer buf, int offset, int fromBit, int numOfBits )
	{
		long val = readLong( buf, offset, fromBit, numOfBits ) ;
		return val ;
	}
}
